/*
"滴滴出行" app 自动签到，支持 Quantumult X（理论上也支持 Surge、Loon，未尝试）。
请先按下述方法进行配置，进入"滴滴出行"，若弹出"首次写入滴滴出行 Token 成功"即可正常食用，先手动运行一次脚本，弹出成功后回到"滴滴出行"，点击右上角"天天领福利"查看福利金是否到账，其他提示或无提示请发送日志信息至 issue。
到 cron 设定时间自动签到时，若弹出"滴滴出行 - 签到成功"即完成签到，其他提示或无提示请发送日志信息至 issue。

⚠️免责声明：
1. 此脚本仅用于学习研究，不保证其合法性、准确性、有效性，请根据情况自行判断，本人对此不承担任何保证责任。
2. 由于此脚本仅用于学习研究，您必须在下载后 24 小时内将所有内容从您的计算机或手机或任何存储设备中完全删除，若违反规定引起任何事件本人对此均不负责。
3. 请勿将此脚本用于任何商业或非法目的，若违反规定请自行对此负责。
4. 此脚本涉及应用与本人无关，本人对因此引起的任何隐私泄漏或其他后果不承担任何责任。
5. 本人对任何脚本引发的问题概不负责，包括但不限于由脚本错误引起的任何损失和损害。
6. 如果任何单位或个人认为此脚本可能涉嫌侵犯其权利，应及时通知并提供身份证明，所有权证明，我们将在收到认证文件确认后删除此脚本。
7. 所有直接或间接使用、查看此脚本的人均应该仔细阅读此声明。本人保留随时更改或补充此声明的权利。一旦您使用或复制了此脚本，即视为您已接受此免责声明。

Author：zZPiglet

----------
版本记录：
- 2020/06/09：
测试阶段，可能会出现各种问题，希望因脚本出现问题可及时反馈。
增加自动签到领取福利金。
脚本中使用了我的邀请打卡 aff（每日最多 5 次，每次 60 福利金。），若不希望使用，可将 aff 改为 false。
代办：增加自动领取打车后未领取的福利金/打车金。
常见错误：
1. 若是 Token 获取问题请先自行排查重写及主机名是否正确，若均正确且日志无报错的情况下无法获取，请反馈，并最好能提供抓包记录（打开抓包软件，然后再进入滴滴，进入打车的界面之后关闭抓包的软件，导出这个包私发给我就行）。
2. 提示"签到失败‼️ 详情请见日志。"，可将日志信息私发给我。若日志信息含有"500 Server internal error"，且着急签到，可尝试将 aff 改为 false 后运行一次脚本，并反馈是否还存在问题。
----------

Quantumult X (App Store:1.0.5+, TestFlight 190+):
[task_local]
1 0 * * * DiDi.js, tag=滴滴出行
or remote
1 0 * * * https://raw.githubusercontent.com/zZPiglet/Task/master/DiDi/DiDi.js, tag=滴滴出行

[rewrite_local]
^https:\/\/as\.xiaojukeji\.com\/ep\/as\/toggles\? url script-request-header DiDi.js
or remote
^https:\/\/as\.xiaojukeji\.com\/ep\/as\/toggles\? url script-request-header https://raw.githubusercontent.com/zZPiglet/Task/master/DiDi/DiDi.js


Surge 4.0+ & Loon:
[Script]
cron "1 0 * * *" script-path=https://raw.githubusercontent.com/zZPiglet/Task/master/DiDi/DiDi.js
http-request ^https:\/\/as\.xiaojukeji\.com\/ep\/as\/toggles\? script-path=https://raw.githubusercontent.com/zZPiglet/Task/master/DiDi/DiDi.js

All app:
[mitm]
hostname = as.xiaojukeji.com

获取完 Token 后可不注释 rewrite / hostname，Token 更新时会弹窗。若因 MitM 导致该软件或小程序网络不稳定，可注释掉 hostname。
*/

const aff = true //若不想提供 aff 请改为 false。
const mainURL = 'https://bosp-api.xiaojukeji.com/wechat/benefit/public/index?'
const TokenName = '滴滴出行'
const TokenKey = 'DiDi'
const CityKey = 'DiDi_city'
const reg = /^https:\/\/as\.xiaojukeji\.com\/ep\/as\/toggles\?.*city=(\d*)&.*ticket=(.*)&/
const source_id = ['WTZs7tfSPrADJ8uLRVMOKA%253D%253D', 'DRKV%252BEcE4Gqn%252BH1mKz2HQg%253D%253D']
const today = new Date().getFullYear() + "-" + ("00" + Number(new Date().getMonth() + 1)).substr(-2) + "-" + ("00" + new Date().getDate()).substr(-2)
const $cmp = compatibility()

!(async () => {
  if ($cmp.isRequest) {
    GetToken()
  } else {
      await Checkin()  
  }
})().finally(() => $cmp.done())

function GetToken() {
    if ($request) {
        const requrl = $request.url
        let TokenValue = decodeURIComponent(reg.exec(requrl)[2])
        let CityValue = reg.exec(requrl)[1]
        $cmp.write(CityValue, CityKey)
        if ($cmp.read(TokenKey) != (undefined || null)) {
            if ($cmp.read(TokenKey) != TokenValue) {
                let token = $cmp.write(TokenValue, TokenKey)
                if (!token) {
                    $cmp.notify("更新" + TokenName + " Token 失败‼️", "", "")
                } else {
                    $cmp.notify("更新" + TokenName + " Token 成功 🎉", "", "")
                }
            }
        } else {
            let token = $cmp.write(TokenValue, TokenKey)
            if (!token) {
                $cmp.notify("首次写入" + TokenName + " Token 失败‼️", "", "")
            } else {
                $cmp.notify("首次写入" + TokenName + " Token 成功 🎉", "", "")
            }
        }
    } else {
        $cmp.notify("写入" + TokenName + "Token 失败‼️", "", "配置错误, 无法读取请求头, ")
    }
}

function Choose(v) {
    let r = Math.floor(Math.random() * Math.floor(2))
    return v[r]
}

function isJSON(str) {
    if (typeof str == 'string') {
        try {
            let obj = JSON.parse(str)
            if (typeof obj == 'object' && obj) {
                return obj
            } else {
                return false
            }
        } catch (e) {
            return false
        }
    }
    return false
}

function Checkin() {
  return new Promise((resolve, reject) => {
    let subTitle = ''
    let detail = ''
    let CheckinURL = mainURL + 'city_id=' + $cmp.read("DiDi_city")
    if (aff) {
        let s_i = Choose(source_id)
        $cmp.log("DiDi aff : \n" + s_i)
        CheckinURL += '&share_source_id=' + s_i + '&share_date=' + today
    }
    const didi = {
        url: CheckinURL,
        headers: {
            "Didi-Ticket": $cmp.read("DiDi"),
        }
    }
    $cmp.get(didi, function(error, response, data) {
        if (!error) {
            if (response.statusCode == 403) {
                subTitle += 'Token 未获取或失效❗'
                detail += '请按脚本开头注释完成配置并首次或重新获取 Token。'
            } else {
                const result = isJSON(data)
                if (result && result.errno == 0) {
                    if(result.data.sign.sign) {
                        subTitle += '签到成功！🚕'
                        let todayearn = Number(result.data.sign.sign.subsidy_state.subsidy_amount + result.data.sign.sign.subsidy_state.extra_subsidy_amount)
                        detail += '签到获得 ' + todayearn + ' 福利金，'
                    } else {
                        subTitle += '重复签到！🚖'
                    }
                    let total = Number(result.data.welfare.carousel_text[0].slice(4))
                    detail += '账户共有 ' + total + ' 福利金，可抵扣 ' + total/100 + ' 元。'
                    if (result.data.notification) {
						for (let message of result.data.notification.reverse()) {
							$.expire += "\n" + message;
						}
					}
                    $cmp.log("DiDi source_id : \n" + result.data.share.source_id)
                } else if (result && result.errno == 101) {
                    subTitle += '签到失败‼️ 城市代码错误。'
                    detail += '请重新获取 Token。\n' + result.errmsg
                } else {
                    subTitle += '签到失败‼️ 详情请见日志。'
                    detail += data
                    $cmp.log("DiDi failed response : \n" + data)
                }
            }
        } else {
            subTitle += '签到接口请求失败，详情请见日志。'
            detail += error
            $cmp.log("DiDi failed response : \n" + error)
        }
        detail += "\n请将 DiDi.js 更改为 DiDi_new.js 使用，此脚本仅作为备份。"
        $cmp.notify(TokenName, subTitle, detail)
        resolve()
    })
  })
}

function compatibility(){const e="undefined"!=typeof $request,t="undefined"!=typeof $httpClient,r="undefined"!=typeof $task,n="undefined"!=typeof $app&&"undefined"!=typeof $http,o="function"==typeof require&&!n,s=(()=>{if(o){const e=require("request");return{request:e}}return null})(),i=(e,s,i)=>{r&&$notify(e,s,i),t&&$notification.post(e,s,i),o&&a(e+s+i),n&&$push.schedule({title:e,body:s?s+"\n"+i:i})},u=(e,n)=>r?$prefs.setValueForKey(e,n):t?$persistentStore.write(e,n):void 0,d=e=>r?$prefs.valueForKey(e):t?$persistentStore.read(e):void 0,l=e=>(e&&(e.status?e.statusCode=e.status:e.statusCode&&(e.status=e.statusCode)),e),f=(e,i)=>{r&&("string"==typeof e&&(e={url:e}),e.method="GET",$task.fetch(e).then(e=>{i(null,l(e),e.body)},e=>i(e.error,null,null))),t&&$httpClient.get(e,(e,t,r)=>{i(e,l(t),r)}),o&&s.request(e,(e,t,r)=>{i(e,l(t),r)}),n&&("string"==typeof e&&(e={url:e}),e.header=e.headers,e.handler=function(e){let t=e.error;t&&(t=JSON.stringify(e.error));let r=e.data;"object"==typeof r&&(r=JSON.stringify(e.data)),i(t,l(e.response),r)},$http.get(e))},p=(e,i)=>{r&&("string"==typeof e&&(e={url:e}),e.method="POST",$task.fetch(e).then(e=>{i(null,l(e),e.body)},e=>i(e.error,null,null))),t&&$httpClient.post(e,(e,t,r)=>{i(e,l(t),r)}),o&&s.request.post(e,(e,t,r)=>{i(e,l(t),r)}),n&&("string"==typeof e&&(e={url:e}),e.header=e.headers,e.handler=function(e){let t=e.error;t&&(t=JSON.stringify(e.error));let r=e.data;"object"==typeof r&&(r=JSON.stringify(e.data)),i(t,l(e.response),r)},$http.post(e))},a=e=>console.log(e),y=(t={})=>{e?$done(t):$done()};return{isQuanX:r,isSurge:t,isJSBox:n,isRequest:e,notify:i,write:u,read:d,get:f,post:p,log:a,done:y}}